﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AzureGames.Model;
using Microsoft.ServiceBus;
using Microsoft.ServiceBus.Messaging;
using Microsoft.WindowsAzure;

namespace AzureGames.Data.Implementation
{
    public class NotificationRepository : INotificationRepository
    {
        private string serviceBusConnectionString = string.Empty;
        private NamespaceManager namespaceManager = null;
        private Uri serviceURI = null;
        private TokenProvider credentials = null;
        private SubscriptionClient client = null;

        public NotificationRepository()
        {
            //CCTODO get rid of hardcoding here
            serviceBusConnectionString = CloudConfigurationManager.GetSetting("ServiceBusConnectionString");
            namespaceManager = NamespaceManager.CreateFromConnectionString(this.serviceBusConnectionString);
            serviceURI = ServiceBusEnvironment.CreateServiceUri("sb", "AzureGames", string.Empty);
            credentials = TokenProvider.CreateSharedSecretTokenProvider("owner", "dCCGf/B5PujtwZ71nNLNAQgKgqxzNFAdNzl3iZDma0o=");
        }



        // this needs to be persistent in azurestorage
        //i think this will be a list of the queue names apart from the general q
        //each playerid will have its own q i think?  
        static List<Guid> _playersToNotify = new List<Guid>();
        // this needs to be persistent in azurestorage
        static List<NotificationRepositoryMessage> _notifications = new List<NotificationRepositoryMessage>();

        public void Attach(string playerID)
        {
            //add a notification here to the topic? 
            CreateSubscription("broadcasttopic", playerID);
            PushNotifications(playerID);
        }

        public void Detach(string playerID)
        {
            //remove notification from the topic
        }

        public void PostNotification(Model.Notification message)
        {
            // with azure storage this would add the action to a queue
            // this would then trigger the notify to be sent
            // if the notify request results in true
            // then the action is removed from the queue
            // if it is false then it probably indicates has logged off
            // the message will then stay in the queue until they are logged in again
            // and in the play game view again

            // add to storage

            //send message to topic
            //I think sub will then send to each subscriber?
            var azureMessage = new BrokeredMessage(message);
            var mf = MessagingFactory.Create(serviceURI, credentials);
            try
            {
                var client = mf.CreateTopicClient("broadcasttopic");
                client.Send(azureMessage);
            }
            catch (TimeoutException)
            {

            }
            catch (MessagingException)
            {
            }
            finally
            {
                //client.
            }
        }

        public event NotifyEventHandler NotifyEvent;

        public void PushNotifications(string playerID)
        {
            //when msg received from subscription forward on
            var mf = MessagingFactory.Create(serviceURI, credentials);
            client =  mf.CreateSubscriptionClient("broadcasttopic", playerID);

            BeginReceive();
        }

        private void BeginReceive()
        {
            try
            {
                if (!client.IsClosed)
                {
                    client.BeginReceive(TimeSpan.FromMinutes(5), MessageReceived, null);
                }
            }
            catch (System.ObjectDisposedException)
            {
                client.Close();
            }
        }

        private void MessageReceived(IAsyncResult iar)
        {
            var msg = client.EndReceive(iar);
            if (msg != null)
            {
               var message = msg.GetBody<Model.Notification>();
                msg.Complete();
                
                if (NotifyEvent != null)
                {
                    NotifyEvent(this, new NotifyEventArgs { Message = message });
                }
            }
        }
        //public void PushNotification(Model.Notification message)
        //{
        //    //when msg received from subscription forward on
        //}

        public void UpdateState(Guid messageID, Notification.STATE state)
        {

        }

        private void CreateTopic(string topicName)
        {
            if (!namespaceManager.TopicExists(topicName))
            {
                namespaceManager.CreateTopic(topicName);
            }
        }

        private void CreateSubscription(string topicName, string subscriptionId)
        {
            if (!namespaceManager.SubscriptionExists(topicName, subscriptionId))
            {
                namespaceManager.CreateSubscription(topicName, subscriptionId);
            }
        }
        // this is used to force the creation of a new object
        private class NotificationRepositoryMessage
        {
            public NotificationRepositoryMessage(Model.Notification message)
            {
                this.CreatedDate = message.CreatedDate;
                this.GameDefinitionID = message.GameDefinitionID;
                this.ID = message.ID;
                this.Message = message.Message;
                this.PlayerID = message.PlayerID;
                this.State = message.State;
                this.UpdatedDate = message.LastUpdatedDate;
            }

            public static implicit operator Notification(NotificationRepositoryMessage message)
            {
                return new Notification
                {
                    CreatedDate = message.CreatedDate,
                    LastUpdatedDate = message.UpdatedDate,
                    GameDefinitionID = message.GameDefinitionID,
                    ID = message.ID,
                    PlayerID = message.PlayerID,
                    Message = message.Message,
                    State = message.State
                };
            }

            public DateTime CreatedDate { get; set; }
            public DateTime UpdatedDate { get; set; }
            public int GameDefinitionID { get; set; }
            public Guid ID { get; set; }
            public string Message { get; set; }
            public string PlayerID { get; set; }
            public Model.Notification.STATE State { get; set; }

        }
    }
}
